#include "icache/panel.h"
#include "icache/mem_cache.h"
#include "icache/disc_cache.h"
#include "icache/coordinator.h"
#include "icache/avi_reader.h"
#include "icache/avi_frame_id.h"
#include "icache/seq_reader.h"
#include "icache/still_footage.h"
#include "icache/deinterlaced_footage.h"
#include "icache/file_sequence.h"
#include "profile/regprofile.h"
#include "mswin/file_dir.h"
#include "xml/stream.h"

#ifdef max
#undef max
#endif

namespace icache {

panel::panel()
{
	_profile.reset(new regprofile(HKEY_CURRENT_USER, "Software\\Pixmart\\icache", true, true));

	MEMORYSTATUS m;
	GlobalMemoryStatus(&m);
	_physical_memory = m.dwTotalPhys;
	_min_mem_cache = _physical_memory / 16;
	_max_mem_cache = std::max(_physical_memory / 2, _physical_memory - 128*1024*1024);

	size_t msize;
	_profile->get("mem_cache_quota", msize, _physical_memory / 4);
	if (msize < _min_mem_cache)
		msize = _min_mem_cache;
	else if (msize > _max_mem_cache)
		msize = _max_mem_cache;
	_mc.reset(new mem_cache(msize));

	disc_size_type dsize;
	_profile->get("disc_cache_quota", dsize, 128LL*1024*1024);
	if (dsize < min_disc_cache())
		dsize = min_disc_cache();

	string dir = _profile->get("disc_cache_root_path", string());
	if (dir.empty()) {
		int size = GetTempPath(0, 0);
		if (size > 0) {
			dir.resize(size);
			GetTempPath(size, &dir[0]);
			dir.resize(size-1);
		}
		dir += "icache\\";
	}

	_dc.reset(new disc_cache(dir, dsize, &avi_frame_id_deserializer()));
	_profile->get("disc_cache_erase_on_exit", _dc->erase_contents_on_exit, _dc->erase_contents_on_exit);

	_coordinator.reset(new icache::coordinator(_mc.get(), _dc.get()));

	avi_prefetch_frames = _profile->get("avi_prefetch_frames", 10);
}

panel::~panel()
{
}

footage_sptr panel::create_footage(const string & filename)
{
	if (mswin::equal_ext(filename, "avi"))
		return create_avi_footage(filename);

	file_sequence seq;
	seq.create_by_example(filename);
	assert(seq.duration() != 0);
	if (seq.duration() == 1)
		return create_still_footage(filename);
	return footage_sptr(new seq_reader(seq, _coordinator.get()));
}

footage_sptr panel::create_footage(xml::stream & s, string const & reference_path)
{
	assert(s.in());

	footage_sptr p;

	string type;
	s || xml::def_attr("type", type);
	if (type.empty())
		return p;

	if (type == "avi")
		p = footage_sptr(new avi_reader(string(), _coordinator.get(), avi_prefetch_frames));
	else if (type == "seq")
		p = footage_sptr(new seq_reader(string(), _coordinator.get()));
	else if (type == "still")
		p = footage_sptr(new still_footage(string(), _coordinator.get()));
	else if (type == "dil") {
		footage_sptr supplier = create_footage(s.child("supplier"), reference_path);
		if (supplier)
			p = footage_sptr(new deinterlaced_footage(supplier));
	}

	if (p)
		p->serialize(s, reference_path);
	return p;
}

footage_sptr panel::create_avi_footage(const string & filename)
{
	return footage_sptr(new avi_reader(filename, _coordinator.get(), avi_prefetch_frames));
}

footage_sptr panel::create_seq_footage(const string & filename)
{
	return footage_sptr(new seq_reader(filename, _coordinator.get()));
}

footage_sptr panel::create_still_footage(const string & filename)
{
	return footage_sptr(new still_footage(filename, _coordinator.get()));
}

cached_image_sptr panel::get_still_image(const string & filename)
{
	return _mc->get(still_image_id::create(filename));
}

cache & panel::coordinator() 
{ 
	return *_coordinator; 
}

size_t panel::mem_cache_size() const
{
	return _mc->size();
}

size_t panel::mem_cache_quota() const
{
	return _mc->quota();
}

disc_size_type panel::disc_cache_size() const
{
	return _dc->size();
}

disc_size_type panel::disc_cache_quota() const
{
	return _dc->quota();
}

void panel::get_data(data & d) const
{
	d.mem_cache_size = _mc->size();
	d.mem_cache_items = _mc->items();
	d.mem_cache_quota = _mc->quota();
	d.disc_cache_size = _dc->size();
	d.disc_cache_items = _dc->items();
	d.disc_cache_quota = _dc->quota();
	d.disc_cache_root_path = _dc->root_path();
	d.disc_cache_erase_on_exit = _dc->erase_contents_on_exit;
	d.avi_prefetch_frames = avi_prefetch_frames;
}

void panel::set_data(data & d)
{
	if (d.mem_cache_quota < min_mem_cache())
		d.mem_cache_quota = min_mem_cache();
	else if (d.mem_cache_quota > max_mem_cache())
		d.mem_cache_quota = max_mem_cache();
	_mc->quota(d.mem_cache_quota);
	d.mem_cache_size = _mc->size();
	d.mem_cache_items = _mc->items();

	_dc->erase_contents_on_exit = d.disc_cache_erase_on_exit;

	if (d.disc_cache_quota < min_disc_cache())
		d.disc_cache_quota = min_disc_cache();
	if (d.disc_cache_root_path != _dc->root_path())
		_dc->reinit(d.disc_cache_root_path, d.disc_cache_quota, &avi_frame_id_deserializer());
	else
		_dc->quota(d.disc_cache_quota);
	d.disc_cache_size = _dc->size();
	d.disc_cache_items = _dc->items();

	if (d.avi_prefetch_frames < 1)
		d.avi_prefetch_frames = 1;
	if (d.avi_prefetch_frames > 1000)
		d.avi_prefetch_frames = 1000;
	avi_prefetch_frames = d.avi_prefetch_frames;
}

void panel::remember(data const & d)
{
	if (!_profile->is_open())
		return;
	_profile->set("mem_cache_quota", d.mem_cache_quota);
	_profile->set("disc_cache_quota", d.disc_cache_quota);
	_profile->set("disc_cache_root_path", d.disc_cache_root_path);
	_profile->set("disc_cache_erase_on_exit", d.disc_cache_erase_on_exit);
	_profile->set("avi_prefetch_frames", d.avi_prefetch_frames);
}

void panel::purge_mem_cache()
	{ _mc->purge(); }

void panel::purge_disc_cache()
	{ _dc->purge(); }

} //namespace icache
